package com.jhws.core.log.service;

import com.aliyun.openservices.log.Client;
import com.aliyun.openservices.log.common.LogContent;
import com.aliyun.openservices.log.common.LogItem;
import com.aliyun.openservices.log.common.QueriedLog;
import com.aliyun.openservices.log.exception.LogException;
import com.aliyun.openservices.log.request.GetHistogramsRequest;
import com.aliyun.openservices.log.request.GetLogsRequest;
import com.aliyun.openservices.log.response.GetHistogramsResponse;
import com.aliyun.openservices.log.response.GetLogsResponse;
import com.jhws.common.Page;
import com.jhws.core.log.bo.LogConstants;
import com.jhws.core.spring.PageContext;
import com.jhws.util.DateUtil;
import com.jhws.util.GsonUtil;
import com.jhws.util.StringUtils;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class LogServiceAliImpl implements ILogService{


    private Client client = new Client(LogConstants.endpoint, LogConstants.accessKeyId, LogConstants.accessKeySecret);


    /**
     * 支持ALI query条件查询的接口
     * @param logStore
     * @param topic
     * @param pageOffset 页起始偏移
     * @param pageSize   页大小
     * @param timeStart  unix 时间戳，秒
     * @param timeEnd    unix 时间戳，秒
     * @param query
     * @return
     * @throws LogException
     * @throws InterruptedException
     */

     private GetLogsResponse getLogsWithQuery(String logStore,String topic, int pageOffset,int pageSize,int timeStart, int timeEnd, String query) throws LogException,InterruptedException {

            GetLogsResponse res4 = null;
            // 对于每个 log offset,一次读取 10 行 log，如果读取失败，最多重复读取 3 次。
            for (int retry_time = 0; retry_time < 3; retry_time++) {
                GetLogsRequest req4 = new GetLogsRequest(LogConstants.projectName, logStore, timeStart, timeEnd, topic, query, pageOffset,
                        pageSize, false);
                res4 = client.GetLogs(req4);
                if (res4 != null && res4.IsCompleted()) {
                    break;
                }
                Thread.sleep(200);
            }
            System.out.println("Read log count:" + String.valueOf(res4.GetCount()));

        return res4;
    }



    private List<Map<String, String>> logItemsToMapList(GetLogsResponse res){
        List<Map<String,String>> retlist = new ArrayList();
        ArrayList<QueriedLog> list = res.GetLogs();
        for(QueriedLog log : list){
            HashMap<String,String> map = new HashMap<>();
            LogItem item = log.GetLogItem();
            ArrayList<LogContent> contents = item.GetLogContents();

            for(LogContent content : contents){
                if(!content.GetKey().startsWith("__"))
                    map.put(content.GetKey(),content.GetValue());
            }
            retlist.add(map);
        }
        return retlist;
    }

    /**
     * 遍历所有查出来的日志，然后寻找message key, 将value转成bean
     * @param res
     * @param clazz
     * @return
     */
    private List<Object> jsonLogsToBeanList(GetLogsResponse res,Class clazz){
        List<Object> retlist = new ArrayList();
        ArrayList<QueriedLog> list = res.GetLogs();
        for(QueriedLog log : list){
            HashMap<String,String> map = new HashMap<>();
            LogItem item = log.GetLogItem();
            ArrayList<LogContent> contents = item.GetLogContents();

            for(LogContent content : contents){
                if(content.GetKey().equals("message"))
                    retlist.add(GsonUtil.toObject(content.GetValue(),clazz,true));
            }
        }
        return retlist;
    }


    /**
     * 将阿里的查询count的返回数据输出成自定义格式
     * @param res - 通过阿里日志库查询返回的数据格式
     * @return
     */
    private Map<String, Object> logItemsToTimeList(GetLogsResponse res){
        int totalCount = 0;
        List<Map<String,String>> retlist = new ArrayList();
        HashMap<String,Object> ret = new HashMap<>();
        ArrayList<QueriedLog> list = res.GetLogs();
        for(QueriedLog log : list){
            HashMap<String,String> map = new HashMap<>();
            LogItem item = log.GetLogItem();
            ArrayList<LogContent> contents = item.GetLogContents();
            map.put("startTime",String.valueOf(item.mLogTime));
            for(LogContent content : contents){
                if(content.GetKey().equals("_c0")) {
                    map.put("count", content.GetValue());
                    totalCount += Integer.valueOf(content.GetValue());
                }
                else if(content.GetKey().equals("end_time"))
                    map.put("endTime",content.GetValue());
            }
            retlist.add(map);
        }

        ret.put("totalcount",totalCount);
        ret.put("itemList",retlist);
        return ret;
    }

    /**
     * 获取在某个查询条件的，基于某个时间段内的log总数
     * @param logstore
     * @param topic
     * @param timeStart
     * @param timeEnd
     * @param query - 阿里云日志查询语法
     * @return
     * @throws LogException
     * @throws InterruptedException
     */
    public long getLogsTotalCount(String logstore,String topic,Integer timeStart,Integer timeEnd,String query) throws Exception{
        GetHistogramsResponse res3 = null;
        while (true) {
            GetHistogramsRequest req3 = new GetHistogramsRequest(LogConstants.projectName, logstore, topic, query, timeStart, timeEnd);
            res3 = client.GetHistograms(req3);
            if (res3 != null && res3.IsCompleted()) // IsCompleted() 返回
            // true，表示查询结果是准确的，如果返回
            // false，则重复查询
            {
                break;
            }
            Thread.sleep(200);
        }

        return res3.GetTotalCount();
    }

    /**
     * 分页查找某个时间段的log
     * @param logStore
     * @param topic
     * @param page
     * @param pageSize
     * @param timeStart
     * @param timeEnd
     * @return
     * @throws LogException
     * @throws InterruptedException
     */
    public Map<String, Object> getLogs(String logStore,String topic,int page,int pageSize,int timeStart, int timeEnd,String query) throws Exception{

        long count = getLogsTotalCount(logStore,topic,timeStart,timeEnd,query);
        long pageOffset = count - (page * pageSize);
        pageOffset = pageOffset < 0?0:pageOffset;
        List list = logItemsToMapList(getLogsWithQuery(logStore,topic,(int)pageOffset,pageSize,timeStart,timeEnd,query));
        Map<String, Object> retMap = new HashMap<>();
        retMap.put("size",count);
        retMap.put("ret_code",1);
        retMap.put("data",list);
        return retMap;
    }

    /**
     * 从json日志中通过query查询log并转成bean List
     *
     * 必须是Log4j.appender模式写入的日志，json key为message
     *
     * @param logStore
     * @param topic
     * @param page
     * @param pageSize
     * @param timeStart
     * @param timeEnd
     * @param query
     * @param clazz 传入的bean class类型
     * @return
     * @throws LogException
     * @throws InterruptedException
     */
    public Map<String,Object> getJsonLogs(String logStore, String topic, int page, int pageSize, int timeStart, int timeEnd, String query, Class clazz)  throws Exception{
        long count = getLogsTotalCount(logStore,topic,timeStart,timeEnd,query);
        int pageOffset = (int)count - (page * pageSize);
        pageSize = pageOffset < 0?pageSize + pageOffset:pageSize;
        pageOffset = pageOffset < 0?0:pageOffset;
        List list = jsonLogsToBeanList(getLogsWithQuery(logStore,topic,(int)pageOffset,pageSize,timeStart,timeEnd,query),clazz);
        Map<String, Object> retMap = new HashMap<>();
        retMap.put("size",count);
        retMap.put("ret_code",1);
        retMap.put("list",list);
        return retMap;
    }

    /**
     * 获取某个小区为单位的按timeslice分片的呼叫次数的分布数据
     * @param logStore
     * @param topic
     * @param commCode
     * @param timeStart
     * @param timeEnd
     * @param sliceMode
     * @return
     * @throws LogException
     * @throws InterruptedException
     */
    public Map<String, Object> getLogsCount(String logStore, String topic ,String commCode, int timeStart, int timeEnd, int sliceMode)throws Exception{
        String query = "";
        if(StringUtils.isNotEmpty(commCode))
            query += "caller ="+commCode+"????????";
        if(sliceMode == ILogService.DAY)
            query += "| timeslice 24h| count";
        else if(sliceMode == ILogService.HOUR)
            query += "| timeslice 1h| count";

        return logItemsToTimeList(getLogsWithQuery(logStore,topic,0,0,timeStart,timeEnd,query));
    }


    /**
     * 从log日志中进行分页查询,给controller使用
     */
    public Map queryPage(String logStore,String topic,Integer timeStart,Integer timeEnd,String query,Class clazz) throws Exception{
        Page page = PageContext.getPage(true);
        if(CollectionUtils.isNotEmpty(page.getList())){
            throw new IllegalStateException("分页查询只能做一次");
        }

        if(timeStart == null || timeStart == 0 || timeEnd == null || timeEnd == 0) {
            timeStart = (int) DateUtil.getTimeStampsNowFmtSec() - 3600 * 24 * 30;
            timeEnd = (int)DateUtil.getTimeStampsNowFmtSec();
        }


        int pageStart = page.getStart() / page.getNumberPerPage() + 1;
        return getJsonLogs(logStore,topic,pageStart,page.getNumberPerPage(),timeStart,timeEnd,query,clazz);
    }

}
